package cn.jtfadmin.base.dict.config.dictEntityAutoConfig;

import cn.jtfadmin.base.dict.service.DictEntityService;
import cn.jtfadmin.base.dict.service.impl.DefaultDictEntityImpl;
import cn.jtfadmin.base.lang.common.service.BaseService;
import cn.jtfadmin.base.lang.common.utils.DynamicCompilerUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.*;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.core.Ordered;
import org.springframework.core.ResolvableType;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.stereotype.Service;
import org.springframework.util.StreamUtils;
import org.springframework.util.StringUtils;

import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.Set;


/**
 * 实体类字典自动配置
 */
public class DictEntityAutoConfiguration implements BeanDefinitionRegistryPostProcessor, ResourceLoaderAware, EnvironmentAware {


    protected ResourceLoader resourceLoader;
    private Environment environment;

    @Override
    public void setResourceLoader(ResourceLoader resourceLoader) {
        this.resourceLoader = resourceLoader;
    }



    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        if(registry instanceof ConfigurableListableBeanFactory) {
            String[] beanDefinitionNames = registry.getBeanDefinitionNames();
            String serviceSource = "";
            try (InputStream repStream = resourceLoader.getResource("classpath:temp/dictEntityService.temp").getInputStream();
            ) {
                serviceSource = StreamUtils.copyToString(repStream, StandardCharsets.UTF_8);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
            for (String beanDefinitionName : beanDefinitionNames) {
                BeanDefinition beanDefinition = registry.getBeanDefinition(beanDefinitionName);
                String beanClassName = beanDefinition.getBeanClassName();
                if(!StringUtils.hasText(beanClassName)){
                    continue;
                }
                Class<?> beanClass = null;
                try {
                    beanClass = resourceLoader.getClassLoader().loadClass(beanClassName);
                } catch (ClassNotFoundException e) {
                    throw new RuntimeException(e);
                }
                if (BaseService.class.isAssignableFrom(beanClass)) {
                    Class<?> entityClass = ResolvableType.forClass(beanClass).as(BaseService.class).getGeneric(0).resolve();
                    if (entityClass != null && ((ConfigurableListableBeanFactory) registry).getBeanNamesForType(
                            ResolvableType.forClassWithGenerics(DictEntityService.class, entityClass)
                    ).length == 0) {
                        String entityName = entityClass.getName();
                        String entitySimpleName = entityClass.getSimpleName();
                        String serviceName = "cn.jtfadmin.base.dict.service.auto.impl." + entitySimpleName + "DictService";
                        String source = serviceSource.replace("[[EntitySimpleName]]", entitySimpleName).replace("[[EntityName]]", entityName);
                        DynamicCompilerUtils.compilerToFile(serviceName, source, ExtDictServiceClassPathResourceLoaderInitializer.extClassDir);
                    }
                }
            }
            ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false);
            scanner.addIncludeFilter(new AnnotationTypeFilter(Service.class));
            scanner.setEnvironment(environment);
            scanner.setResourceLoader(resourceLoader);
            Set<BeanDefinition> candidateComponents = scanner.findCandidateComponents("cn.jtfadmin.base.dict.service.auto.impl");
            for (BeanDefinition candidateComponent : candidateComponents) {
                registry.registerBeanDefinition(BeanDefinitionReaderUtils.generateBeanName(candidateComponent, registry), candidateComponent);
            }

        }
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {

    }

    @Override
    public void setEnvironment(Environment environment) {
        this.environment = environment;
    }
}
